package home.project.misc;

import openfl.geom.Point;
import openfl.geom.Matrix;
import openfl.display.Graphics;
import openfl.geom.Rectangle;

/**
 * ...
 * @author an.vuongngocduy
 */
class Entity
{
	private var __children:Array<Entity>;
	
	private var __boundingBoxes:Array<Rect>;
	
	private var __relativePostion:Point;
	
	public var id(default, null):Int;
	
	public var name(default, null):String;		
	
	public var absoluteTransform(default, null):Matrix;
	
	//! The relative position to parent object
	public var position(get, set):Point;
	
	public var rotation(default, set):Point;
	
	public var scale(default, set):Point;
	
	//horizontal and vertical velocity
	public var velocity(default, default):Point;
	
	//horizotal and vertical acceleration
	public var acceleration(default, default):Point;
	
	public var parent(default, null):Entity;	
	
	public var children(get, null):Iterator<Entity>;
	
	public var isEnabled(default, default):Bool;
	
	public var isCollidable(default, default):Bool;
	
	public var hasCollision(default, null):Int;
	
	public var boundingBoxes(get, null):Iterator<Rect>;
	
	public var collisionCallback(default, null):Iterator<Entity->Entity->Void>;
		
	public function new() {
		absoluteTransform = new Matrix();
		__relativePostion = new Point();
		velocity = new Point();
		acceleration = new Point();
		__children = new Array<Entity>();
		__boundingBoxes = new Array<Rect>();	
	}
	
	public function get_position():Point {
		return __relativePostion;
	}
	
	public function set_position(p_pos:Point):Point {
		__relativePostion.x = p_pos.x;
		__relativePostion.y = p_pos.y;
		var px:Float = 0;
		var py:Float = 0;
		if (parent != null) {
			px = parent.absoluteTransform.tx;
			py = parent.absoluteTransform.ty;
		}
		//! also , update the absolute object postion
		absoluteTransform.tx = px + __relativePostion.x;
		absoluteTransform.ty = py + __relativePostion.y;
		
		for (c in __children) {
			c.position = c.position; //call to update absolute position
		}
		return position;
	}
	
	public function set_rotation(p_rot:Point):Point {
		return rotation;
	}
	
	public function set_scale(p_scale:Point):Point {
		return scale;
	}
	
	public function get_children():Iterator<Entity> {
		return __children.iterator();
	}
	
	public function get_boundingBoxes():Iterator<Rect> {
		return __boundingBoxes.iterator();
	}
		
	public function draw(p_g:Graphics):Void {
		//! do nothing
	}
	
	public function update(p_dt:Float):Void {
		velocity.offset(acceleration.x * (Globals.sElapsedTime / 1000.0), acceleration.y * (Globals.sElapsedTime / 1000.0));
		position = new Point(__relativePostion.x + velocity.x * (Globals.sElapsedTime / 1000.0),
							 __relativePostion.y + velocity.y * (Globals.sElapsedTime / 1000.0));
	}

	public function addChild(p_child:Entity):Void {
		if(p_child.parent != null){
			p_child.parent.__children.remove(p_child);
		}	
		p_child.parent = this;	
		this.__children.push(p_child);	
		p_child.position = new Point(
			p_child.absoluteTransform.tx  - this.absoluteTransform.tx, 
			p_child.absoluteTransform.ty  - this.absoluteTransform.ty
		);
	}
}